#!/usr/bin/python

import unittest
import expressions
import arithmetic_parser, arithmetic_compiler

class expressionsTests(unittest.TestCase):
  def test_expression_no_eq(self):
    exp = expressions.Expression("", {})
    self.assertEquals(exp._variables, {})
    self.assertEquals(exp.expression, "") 
    self.assertEquals(exp._is_readonly, True)
    
    
  def test_rearrange_expression(self):
    exp = expressions.Expression("x==y", {}, has_eq=True)
    self.assertEqual(exp._rearrange_expression("y==3+5"), "y==3+5")
    self.assertEqual(exp._rearrange_expression("3+5==y"), "y==3+5")
    self.assertEqual(exp._rearrange_expression("y+x==3+5"), "y+x==3+5")
    self.assertEqual(exp._rearrange_expression("3+5==y+x"), "y+x==3+5")
    self.assertEqual(exp._rearrange_expression("0==y+x"), "y+x==0")
    self.assertEqual(exp._rearrange_expression("5==8"), "8==5")
    self.assertEqual(exp._rearrange_expression("x==y"), "x==y")
    exp = expressions.Expression("", {}, has_eq=False)
    self.assertEqual(exp._rearrange_expression("y3+5"), "y3+5")
    self.assertEqual(exp._rearrange_expression("3+5y"), "3+5y")
    self.assertEqual(exp._rearrange_expression("y+x"), "y+x")
    self.assertEqual(exp._rearrange_expression("3+5-y+x"), "3+5-y+x")
    self.assertEqual(exp._rearrange_expression("0*y+x"), "0*y+x")
    self.assertEqual(exp._rearrange_expression("58"), "58")
    self.assertEqual(exp._rearrange_expression("x/y"), "x/y")
    
    
  def test__calculate_is_readonly_with_eq(self):
    y_var = expressions.Variable(3)
    x_var = expressions.Variable(3)
    exp = expressions.Expression("(x)==(3+y)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), False)
    exp = expressions.Expression("(x+y)==(10)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), True)
    exp = expressions.Expression("(x+y)==(10+x*5)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), True)
    exp = expressions.Expression("(15)==(10+x*5)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), False)
    exp = expressions.Expression("(x)==(3+y+x)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), False)
    exp = expressions.Expression("(4)==(3+y+x)", {'y' : y_var, 'x' : x_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), True)
    x_var = expressions.Variable(True)
    y_var = expressions.Variable(False)
    exp = expressions.Expression("(x)==(y)", {'x' : x_var, 'y' : y_var}, has_eq=True)
    self.assertEquals(exp._calculate_is_readonly(), False)
    
    
  def test__calculate_is_readonly_without_eq(self):
    y_var = expressions.Variable(3)
    x_var = expressions.Variable(3)
    exp = expressions.Expression("3", {}, has_eq=False)
    self.assertEquals(exp._calculate_is_readonly(), True)
    exp = expressions.Expression("x", {'x' : x_var}, has_eq=False)
    self.assertEquals(exp._calculate_is_readonly(), False) 
    x_var = expressions.Variable(True)
    y_var = expressions.Variable(False)
    exp = expressions.Expression("x", {'x' : x_var}, has_eq=False)
    self.assertEquals(exp._calculate_is_readonly(), False) 
    
    
  def test_evaluateBool(self):
    x_var = expressions.Variable(3)
    y_var = expressions.Variable(6)
    exp = expressions.Expression("(x)==(y)", {'x' : x_var})
    self.assertEquals(exp._evaluateBool("(y)==(x+3)", 'y', True), False)
    self.assertEquals(exp._evaluateBool("(y)==(x)", 'y', True), False)
    self.assertEquals(exp._evaluateBool("3", 'y', True), False)
    self.assertEquals(exp._evaluateBool("3", 'y', False), False)
    self.assertEquals(exp._evaluateBool("(8)==(x+7+y-2)", 'y', False), True)
    self.assertEquals(exp._evaluateBool("(14)==(x+7+y-2)", 'y', False), True)
    x_var = expressions.Variable(True)
    y_var = expressions.Variable(True)
    exp = expressions.Expression("(x)==(y)", {'y' : y_var})
    self.assertEquals(exp._evaluateBool("(x)==(y)", 'x', True), True)
    self.assertEquals(exp._evaluateBool("(x)==(not x or y)", 'x', True), True)
    self.assertEquals(exp._evaluateBool("(x)==(not x or not y)", 'x', True), False)
    self.assertEquals(exp._evaluateBool("(x)==(not y or not y)", 'x', True), False)
    exp = expressions.Expression("(x)==(y)", {})
    self.assertEquals(exp._evaluateBool("2*x+4", 'x', True), False)
    self.assertEquals(exp._evaluateBool("1 and x", 'x', True), True)
    self.assertEquals(exp._evaluateBool("0 and x or (4+7*50)", 'x', True), False)
    
    
  def test_find_single_var_name(self):
    exp = expressions.Expression("x==y", {})
    self.assertEquals(exp._find_single_var_name("x==y+5"), None)
    self.assertEquals(exp._find_single_var_name("45"), None)
    self.assertEquals(exp._find_single_var_name("4==x+3+x*4"), 'x')
    self.assertEquals(exp._find_single_var_name(""), None)
    self.assertEquals(exp._find_single_var_name("10==1+2+3+4"), None)
    self.assertEquals(exp._find_single_var_name("y==x+y+z-3"), None)

    
  def test_evaluateTo_simple(self):
    #has_eq=True
    x_var = expressions.Variable(5+7)
    exp = expressions.Expression("(x)==(2)", {'x' : x_var}, expressions.ExpressionType.SIMPLE, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), 2)
    exp = expressions.Expression("(x)==(2+4*50/3)", {'x' : x_var}, expressions.ExpressionType.SIMPLE, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), eval("2+4*50/3"))
    #has_eq=False
    x_var = expressions.Variable(5+7)
    exp = expressions.Expression("x", {'x' : x_var}, expressions.ExpressionType.SIMPLE, False)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), True)
    
    
  def test_evaluateTo_bool_with_eq(self):
    x_var = expressions.Variable(True)
    y_var = expressions.Variable(4)
    exp = expressions.Expression("(x)==(y)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), False)
    self.assertEquals(exp.getVariables()['y'].getValue(), 4)
    y_var = expressions.Variable(True)
    exp = expressions.Expression("(x)==(y)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), True)
    self.assertEquals(exp.getVariables()['y'].getValue(), True)
    exp = expressions.Expression("(x)==(y and not 0)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), True)
    exp = expressions.Expression("(x)==(not 5 or not 0 or not y)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), True)
    
    
  def test_evaluateTo_bool_without_eq(self):
    #has_eq=False
    x_var = expressions.Variable(True)
    exp = expressions.Expression("x", {'x' : x_var}, expressions.ExpressionType.BOOL, False)
    exp.evaluateTo(False)
    self.assertEquals(exp.getVariables()['x'].getValue(), False)
    exp = expressions.Expression("x and 4*0 or x+0", {'x' : x_var}, expressions.ExpressionType.BOOL, False)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), True)
    exp.evaluateTo(False)
    self.assertEquals(exp.getVariables()['x'].getValue(), False)
    
    
  def test_evaluateTo_math(self):
    #has_eq=True
    x_var = expressions.Variable(4)
    y_var = expressions.Variable(4)
    z_var = expressions.Variable(True)
    w_var = expressions.Variable(43)
    exp = expressions.Expression("(x)==(y)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.MATH, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), 4)
    exp = expressions.Expression("(x)==(y+14-8)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.MATH, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), 10)
    exp = expressions.Expression("(x)==(y+z-8+2*w)", {'x' : x_var, 'y' : y_var, 'z' :z_var, 'w' : w_var}, expressions.ExpressionType.MATH, True)
    exp.evaluateTo(True)
    self.assertEquals(exp.getVariables()['x'].getValue(), 83)
    #has_eq=False
    exp = expressions.Expression("y+14-8", {'y' : y_var}, expressions.ExpressionType.MATH, False)
    exp.evaluateTo(10)
    self.assertEquals(exp.getVariables()['y'].getValue(), 4)
    
    
    
  def test_evaluateTo_readonly(self):
    #for readonly
    x_var = expressions.Variable(True)
    y_var = expressions.Variable(True)
    exp = expressions.Expression("10", {}, expressions.ExpressionType.SIMPLE, False)
    self.assertRaises(expressions.ReadonlyError, exp.evaluateTo, 10)
    exp = expressions.Expression("x and y and 4*0", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, False)
    self.assertRaises(expressions.ReadonlyError, exp.evaluateTo, False)
    x_var = expressions.Variable(18)
    y_var = expressions.Variable(-6)
    exp = expressions.Expression("(x+y)==(12)", {'x' : x_var, 'y' : y_var}, expressions.ExpressionType.BOOL, True)
    self.assertRaises(expressions.ReadonlyError, exp.evaluateTo, True)
    
if __name__ == '__main__':
  import unittest
  unittest.main()
    
